package com.itls.recommendedgames.service.Impl;

import com.itls.recommendedgames.entity.Game;
import com.itls.recommendedgames.entity.GamePopularity;
import com.itls.recommendedgames.entity.User;
import com.itls.recommendedgames.mapper.GameMapper;
import com.itls.recommendedgames.service.RecommendationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class RecommendationServiceImpl implements RecommendationService {

    @Autowired
    private GameMapper gameMapper;

    /**
     * 个人个性化推荐算法（基于混合推荐，包含游玩时间、个人标签推荐、类型用户）
     */
    @Override
    public List<Game> getPersonalizedRecommendations(User user, int limit) {
        if (user == null || user.getId() == 0 || limit <= 0) {
            return getFallbackRecommendations(limit);
        }

        // 1. 分析用户类型
        String userType = analyzeUserType(user);

        // 2. 获取用户已拥有的游戏ID列表
        List<Integer> ownedGameIds = gameMapper.getUserOwnedGameIds(user.getId());

        // 如果没有已拥有的游戏，使用热门推荐
        if (ownedGameIds == null || ownedGameIds.isEmpty()) {
            return getPopularGames(limit, true);
        }

        // 3. 获取用户游玩时长数据
        Map<Integer, Double> playTimeMap = getUserPlayTimeMapAsMap(user.getId());

        // 4. 获取用户标签偏好（带游玩时长权重）
        Map<String, Double> userTagWeights = getUserTagFrequencyWithPlayTime(ownedGameIds, playTimeMap);

        // 5. 获取相似用户（结合传统协同过滤和游玩时长相似度）
        List<Integer> traditionalSimilarUsers = getSimilarUsers(user.getId());
        List<Integer> playTimeSimilarUsers = getSimilarUsersByPlayTime(user.getId());
        
        Set<Integer> allSimilarUsers = new HashSet<>();
        if (traditionalSimilarUsers != null) {
            allSimilarUsers.addAll(traditionalSimilarUsers);
        }
        if (playTimeSimilarUsers != null) {
            allSimilarUsers.addAll(playTimeSimilarUsers);
        }

        // 6. 获取相似用户喜欢的游戏
        Set<Integer> collaborativeGameIds = new HashSet<>();
        if (!allSimilarUsers.isEmpty()) {
            for (Integer similarUserId : allSimilarUsers) {
                if (similarUserId != null) {
                    List<Integer> likedGames = gameMapper.getUserOwnedGameIds(similarUserId);
                    if (likedGames != null) {
                        collaborativeGameIds.addAll(likedGames);
                    }
                }
            }
            if (ownedGameIds != null) {
                collaborativeGameIds.removeAll(ownedGameIds);
            }
        }

        // 7. 基于标签相似度获取游戏
        Set<Integer> tagBasedGameIds = new HashSet<>();
        if (userTagWeights != null && !userTagWeights.isEmpty()) {
            List<String> preferredTags = new ArrayList<>(userTagWeights.keySet());
            List<Integer> tagBasedGames = getSimilarGamesByTags(preferredTags, limit * 2);
            if (tagBasedGames != null) {
                tagBasedGameIds.addAll(tagBasedGames);
            }
        }

        // 8. 根据用户类型调整推荐策略
        Set<Integer> finalRecommendedGameIds = adjustRecommendationsByUserType(
                userType, collaborativeGameIds, tagBasedGameIds, ownedGameIds, limit);

        // 9. 如果推荐列表为空，使用热门推荐
        if (finalRecommendedGameIds.isEmpty()) {
            return getPopularGames(limit, true);
        }

        // 10. 获取推荐游戏的详细信息
        List<Game> recommendedGames = getAllGamesByIds(new ArrayList<>(finalRecommendedGameIds));

        // 11. 计算每个游戏的个性化得分
        Map<Integer, Map<String, Integer>> allGameTagFrequencies = getAllGameTagFrequencies();
        Map<Integer, Double> finalScoreMap = calculatePersonalizedGameScores(
                recommendedGames, userTagWeights, allGameTagFrequencies, 
                collaborativeGameIds, playTimeMap, userType);

        // 12. 排序并选择前limit个游戏
        List<Game> finalRecommendations = getTopScoredGames(recommendedGames, finalScoreMap, limit);

        return finalRecommendations;
    }

    /**
     * 分析用户类型
     */
    @Override
    public String analyzeUserType(User user) {
        if (user == null || user.getId() == 0) {
            return "NEW_USER";
        }

        // 获取用户游戏数据
        List<Integer> ownedGameIds = gameMapper.getUserOwnedGameIds(user.getId());
        Map<Integer, Double> playTimeMap = getUserPlayTimeMapAsMap(user.getId());

        if (ownedGameIds == null || ownedGameIds.isEmpty()) {
            return "NEW_USER";
        }

        // 计算用户特征
        int totalGames = ownedGameIds.size();
        double totalPlayTime = playTimeMap.values().stream().mapToDouble(Double::doubleValue).sum();
        double avgPlayTime = totalPlayTime / totalGames;
        
        // 获取高游玩时长游戏数量
        long highPlayTimeGames = playTimeMap.values().stream()
                .filter(time -> time > 50.0) // 超过50小时
                .count();

        // 分析用户类型
        if (totalGames < 5) {
            return "CASUAL_GAMER"; // 休闲玩家
        } else if (avgPlayTime > 100.0 && highPlayTimeGames > 3) {
            return "HARDCORE_GAMER"; // 硬核玩家
        } else if (avgPlayTime > 30.0) {
            return "REGULAR_GAMER"; // 常规玩家
        } else {
            return "CASUAL_GAMER"; // 休闲玩家
        }
    }

    /**
     * 根据用户类型调整推荐策略
     */
    private Set<Integer> adjustRecommendationsByUserType(String userType, 
                                                        Set<Integer> collaborativeGameIds,
                                                        Set<Integer> tagBasedGameIds,
                                                        List<Integer> ownedGameIds,
                                                        int limit) {
        Set<Integer> finalGameIds = new HashSet<>();

        switch (userType) {
            case "NEW_USER":
                // 新用户：主要推荐热门游戏
                List<Game> popularGames = getPopularGames(limit, true);
                if (popularGames != null) {
                    for (Game game : popularGames) {
                        if (game != null && game.getId() != null) {
                            finalGameIds.add(game.getId());
                        }
                    }
                }
                break;
                
            case "CASUAL_GAMER":
                // 休闲玩家：平衡协同过滤和标签推荐，偏向热门游戏
                if (collaborativeGameIds != null) {
                    finalGameIds.addAll(collaborativeGameIds);
                }
                if (tagBasedGameIds != null) {
                    finalGameIds.addAll(tagBasedGameIds);
                }
                // 添加一些热门游戏
                List<Game> casualPopular = getPopularGames(limit / 2, true);
                if (casualPopular != null) {
                    for (Game game : casualPopular) {
                        if (game != null && game.getId() != null) {
                            finalGameIds.add(game.getId());
                        }
                    }
                }
                break;
                
            case "REGULAR_GAMER":
                // 常规玩家：主要基于协同过滤和标签推荐
                if (collaborativeGameIds != null) {
                    finalGameIds.addAll(collaborativeGameIds);
                }
                if (tagBasedGameIds != null) {
                    finalGameIds.addAll(tagBasedGameIds);
                }
                break;
                
            case "HARDCORE_GAMER":
                // 硬核玩家：更注重标签推荐和深度游戏
                if (tagBasedGameIds != null) {
                    finalGameIds.addAll(tagBasedGameIds);
                }
                if (collaborativeGameIds != null) {
                    finalGameIds.addAll(collaborativeGameIds);
                }
                break;
                
            default:
                if (collaborativeGameIds != null) {
                    finalGameIds.addAll(collaborativeGameIds);
                }
                if (tagBasedGameIds != null) {
                    finalGameIds.addAll(tagBasedGameIds);
                }
                break;
        }

        // 过滤已拥有的游戏
        if (ownedGameIds != null) {
            finalGameIds.removeAll(ownedGameIds);
        }
        
        return finalGameIds;
    }

    /**
     * 计算个性化游戏得分
     */
    private Map<Integer, Double> calculatePersonalizedGameScores(List<Game> recommendedGames,
                                                               Map<String, Double> userTagWeights,
                                                               Map<Integer, Map<String, Integer>> allGameTagFrequencies,
                                                               Set<Integer> collaborativeGameIds,
                                                               Map<Integer, Double> playTimeMap,
                                                               String userType) {
        Map<Integer, Double> finalScoreMap = new HashMap<>();

        if (recommendedGames != null) {
            for (Game game : recommendedGames) {
                if (game == null || game.getId() == null) {
                    continue;
                }
                
                Integer gameId = game.getId();
                double score = 0.0;

                // 1. 标签匹配得分（带游玩时长权重）
                if (userTagWeights != null && !userTagWeights.isEmpty()) {
                    Map<String, Integer> gameTags = allGameTagFrequencies.getOrDefault(gameId, Collections.emptyMap());
                    double tagScore = 0.0;
                    for (String userTag : userTagWeights.keySet()) {
                        if (gameTags.containsKey(userTag)) {
                            tagScore += userTagWeights.get(userTag);
                        }
                    }
                    score += tagScore * 3.0; // 提高标签匹配权重
                }

                // 2. 协同过滤得分
                if (collaborativeGameIds != null && collaborativeGameIds.contains(gameId)) {
                    score += 2.0;
                }

                // 3. 游玩时长偏好得分
                if (playTimeMap != null) {
                    double playTimeScore = calculatePlayTimePreferenceScore(gameId, playTimeMap, allGameTagFrequencies);
                    score += playTimeScore * 2.0;
                }

                // 4. 游戏评分得分
                if (game.getRating() != null) {
                    double normalizedRating = game.getRating().doubleValue() / 5.0;
                    score += normalizedRating * 1.5;
                }

                // 5. 根据用户类型调整得分
                score = adjustScoreByUserType(score, userType, game);

                finalScoreMap.put(gameId, score);
            }
        }

        return finalScoreMap;
    }


    /**
     * 根据用户类型调整得分
     */
    private double adjustScoreByUserType(double baseScore, String userType, Game game) {
        switch (userType) {
            case "NEW_USER":
                // 新用户：更重视游戏评分和流行度
                // 使用 BigDecimal.valueOf(4.0) 创建一个 BigDecimal 对象进行比较
                if (game.getRating() != null && game.getRating().compareTo(BigDecimal.valueOf(4.0)) >= 0) {
                    return baseScore * 1.2;
                }
                break;

            case "CASUAL_GAMER":
                // 休闲玩家：偏好简单易上手的游戏
                if (game.getTags() != null && game.getTags().contains("casual")) {
                    return baseScore * 1.3;
                }
                break;

            case "HARDCORE_GAMER":
                // 硬核玩家：偏好复杂、深度游戏
                if (game.getTags() != null &&
                        (game.getTags().contains("strategy") ||
                                game.getTags().contains("rpg") ||
                                game.getTags().contains("simulation"))) {
                    return baseScore * 1.3;
                }
                break;
        }

        return baseScore;
    }
    @Override
    public List<Integer> getSimilarUsersByPlayTime(Integer userId) {
        return gameMapper.getSimilarUsersByPlayTime(userId, 5);
    }

    /**
     * 获取用户游玩时长数据并转换为Map格式
     */
    private Map<Integer, Double> getUserPlayTimeMapAsMap(Integer userId) {
        List<Map<String, Object>> playTimeList = gameMapper.getUserPlayTimeMap(userId);
        Map<Integer, Double> playTimeMap = new HashMap<>();
        
        if (playTimeList != null) {
            for (Map<String, Object> item : playTimeList) {
                Integer gameId = (Integer) item.get("gameId");
                Object playTimeObj = item.get("playTimeHours");
                Double playTime = 0.0;
                
                if (playTimeObj instanceof java.math.BigDecimal) {
                    playTime = ((java.math.BigDecimal) playTimeObj).doubleValue();
                } else if (playTimeObj instanceof Double) {
                    playTime = (Double) playTimeObj;
                } else if (playTimeObj instanceof Number) {
                    playTime = ((Number) playTimeObj).doubleValue();
                }
                
                if (gameId != null && playTime > 0) {
                    playTimeMap.put(gameId, playTime);
                }
            }
        }
        
        return playTimeMap;
    }


    /**
     * 备用推荐方案
     */
    private List<Game> getFallbackRecommendations(int limit) {
        // 返回高评分游戏作为备用
        List<Game> fallbackGames = gameMapper.getHighRatedGames(limit);
        return fallbackGames != null ? fallbackGames : Collections.emptyList();
    }

    /**
     * 获取用户已拥有游戏的标签频率
     */
    public Map<String, Integer> getUserTagFrequency(List<Integer> ownedGameIds) {
        if (ownedGameIds == null || ownedGameIds.isEmpty()) {
            return Collections.emptyMap();
        }

        List<Game> ownedGames = gameMapper.findGamesByIds(ownedGameIds);
        if (ownedGames == null || ownedGames.isEmpty()) {
            return Collections.emptyMap();
        }

        // 统计标签频率
        Map<String, Integer> tagFrequency = new HashMap<>();
        for (Game game : ownedGames) {
            Set<String> tags = game.getTags();
            if (tags != null && !tags.isEmpty()) {
                for (String tag : tags) {
                    String trimmedTag = tag.trim().toLowerCase();
                    if (!trimmedTag.isEmpty()) {
                        tagFrequency.put(trimmedTag, tagFrequency.getOrDefault(trimmedTag, 0) + 1);
                    }
                }
            }
        }

        return tagFrequency;
    }

    /**
     * 获取用户已拥有游戏的标签频率（带游玩时长权重）
     */
    public Map<String, Double> getUserTagFrequencyWithPlayTime(List<Integer> ownedGameIds, Map<Integer, Double> playTimeMap) {
        if (ownedGameIds == null || ownedGameIds.isEmpty()) {
            return Collections.emptyMap();
        }

        List<Game> ownedGames = gameMapper.findGamesByIds(ownedGameIds);
        if (ownedGames == null || ownedGames.isEmpty()) {
            return Collections.emptyMap();
        }

        // 统计标签频率（带游玩时长权重）
        Map<String, Double> tagFrequency = new HashMap<>();
        for (Game game : ownedGames) {
            Set<String> tags = game.getTags();
            if (tags != null && !tags.isEmpty()) {
                // 获取该游戏的游玩时长，如果没有记录则默认为1小时
                double playTime = playTimeMap.getOrDefault(game.getId(), 1.0);
                // 使用对数函数来平滑游玩时长的影响，避免极值影响过大
                double weight = Math.log(playTime + 1.0);
                
                for (String tag : tags) {
                    String trimmedTag = tag.trim().toLowerCase();
                    if (!trimmedTag.isEmpty()) {
                        tagFrequency.put(trimmedTag, tagFrequency.getOrDefault(trimmedTag, 0.0) + weight);
                    }
                }
            }
        }

        return tagFrequency;
    }



    /**
     * 计算游玩时长偏好得分
     */
    private double calculatePlayTimePreferenceScore(Integer gameId, 
                                                   Map<Integer, Double> playTimeMap,
                                                   Map<Integer, Map<String, Integer>> allGameTagFrequencies) {
        if (playTimeMap.isEmpty()) {
            return 0.0;
        }

        Map<String, Integer> gameTags = allGameTagFrequencies.getOrDefault(gameId, Collections.emptyMap());
        if (gameTags.isEmpty()) {
            return 0.0;
        }

        double totalPlayTime = 0.0;
        int matchingGames = 0;

        // 计算用户对具有相似标签游戏的游玩时长
        for (Map.Entry<Integer, Double> entry : playTimeMap.entrySet()) {
            Integer userGameId = entry.getKey();
            Double playTime = entry.getValue();
            
            Map<String, Integer> userGameTags = allGameTagFrequencies.getOrDefault(userGameId, Collections.emptyMap());
            
            // 计算标签重叠度
            long commonTags = gameTags.keySet().stream()
                    .filter(userGameTags::containsKey)
                    .count();
            
            if (commonTags > 0) {
                // 根据标签重叠度加权游玩时长
                double weight = (double) commonTags / Math.max(gameTags.size(), userGameTags.size());
                totalPlayTime += playTime * weight;
                matchingGames++;
            }
        }

        if (matchingGames == 0) {
            return 0.0;
        }

        // 返回平均加权游玩时长，使用对数函数平滑
        double avgPlayTime = totalPlayTime / matchingGames;
        return Math.log(avgPlayTime + 1.0) * 0.5;
    }

    /**
     * 获取得分最高的游戏
     */
    private List<Game> getTopScoredGames(List<Game> recommendedGames,
                                         Map<Integer, Double> finalScoreMap,
                                         int limit) {
        // 创建游戏ID到游戏对象的映射
        Map<Integer, Game> gameMap = recommendedGames.stream()
                .collect(Collectors.toMap(Game::getId, game -> game));

        // 排序并选择前limit个
        return finalScoreMap.entrySet().stream()
                .sorted(Map.Entry.<Integer, Double>comparingByValue().reversed())
                .limit(limit)
                .map(entry -> gameMap.get(entry.getKey()))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 获取所有游戏的标签频率
     */
    public Map<Integer, Map<String, Integer>> getAllGameTagFrequencies() {
        List<Game> allGames = gameMapper.findAllGamesWithTags();
        if (allGames == null || allGames.isEmpty()) {
            return Collections.emptyMap();
        }

        Map<Integer, Map<String, Integer>> gameTagFrequencies = new HashMap<>();
        for (Game game : allGames) {
            Map<String, Integer> tagMap = new HashMap<>();
            Set<String> tags = game.getTags();
            if (tags != null && !tags.isEmpty()) {
                // 修复：直接遍历Set<String> tags
                for (String tag : tags) {
                    String trimmedTag = tag.trim().toLowerCase();
                    if (!trimmedTag.isEmpty()) {
                        tagMap.put(trimmedTag, tagMap.getOrDefault(trimmedTag, 0) + 1);
                    }
                }
            }
            gameTagFrequencies.put(game.getId(), tagMap);
        }
        return gameTagFrequencies;
    }

    public Map<Integer, Double> getGamePopularityScores() {
        List<GamePopularity> popularityScores = gameMapper.getGamePopularityScores();
        if (popularityScores == null || popularityScores.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<Integer, Double> map = new HashMap<>();
        for (GamePopularity gp : popularityScores) {
            map.put(gp.getGameId(), (double) gp.getPopularityScore());
        }
        return map;
    }

    public List<Integer> getSimilarUsers(Integer userId) {
        return gameMapper.getSimilarUsers(userId, 5);
    }

    public List<Integer> getSimilarGamesByTags(List<String> tagNames, int limit) {
        if (tagNames == null || tagNames.isEmpty()) {
            return Collections.emptyList();
        }
        return gameMapper.getSimilarGamesByTags(tagNames, limit);
    }

    public List<Game> getAllGamesByIds(List<Integer> gameIds) {
        if (gameIds == null || gameIds.isEmpty()) {
            return Collections.emptyList();
        }
        return gameMapper.findGamesByIds(gameIds);
    }


    /**
     * 热门游戏推荐算法（改进版）
     */
    @Override
    public List<Game> getPopularGames(int limit, boolean includeTrending) {
        List<Game> popularGames;
        
        if (includeTrending) {
            // 综合评分和流行度的热门游戏
            popularGames = getTrendingGames(limit);
        } else {
            // 传统高评分游戏
            popularGames = gameMapper.getHighRatedGames(limit);
        }
        
        return popularGames;
    }

    /**
     * 为用户定制的热门游戏推荐算法（过滤用户已拥有的游戏）
     */
    @Override
    public List<Game> getPopularGamesForUser(Integer userId, int limit, boolean includeTrending) {
        if (userId == null || userId <= 0) {
            return getPopularGames(limit, includeTrending);
        }

        // 获取用户已拥有的游戏ID列表
        List<Integer> ownedGameIds = gameMapper.getUserOwnedGameIds(userId);

        List<Game> popularGames;
        
        if (includeTrending) {
            // 综合评分和流行度的热门游戏
            popularGames = getTrendingGames(limit * 2); // 获取更多候选游戏
        } else {
            // 传统高评分游戏
            popularGames = gameMapper.getHighRatedGames(limit * 2); // 获取更多候选游戏
        }

        if (popularGames == null || popularGames.isEmpty()) {
            return Collections.emptyList();
        }

        // 过滤掉用户已拥有的游戏
        if (ownedGameIds != null && !ownedGameIds.isEmpty()) {
            popularGames = popularGames.stream()
                    .filter(game -> game != null && game.getId() != null)
                    .filter(game -> !ownedGameIds.contains(game.getId()))
                    .collect(Collectors.toList());
        }

        // 限制返回数量
        if (popularGames.size() > limit) {
            popularGames = popularGames.subList(0, limit);
        }
        
        return popularGames;
    }


    /**
     * 获取趋势游戏（综合评分和流行度）
     */
    /**
     * 获取趋势游戏（综合评分和流行度）
     */
    private List<Game> getTrendingGames(int limit) {
        // 获取高评分游戏
        List<Game> highRatedGames = gameMapper.getHighRatedGames(limit * 2);

        // 获取流行度得分
        Map<Integer, Double> popularityScores = getGamePopularityScores();

        // 计算趋势得分
        Map<Integer, Double> trendingScores = new HashMap<>();
        for (Game game : highRatedGames) {
            double ratingScore = game.getRating() != null ? game.getRating().doubleValue() : 0.0;
            double popularityScore = popularityScores.getOrDefault(game.getId(), 0.0);

            // 综合评分和流行度
            double trendingScore = ratingScore * 0.7 + popularityScore * 0.3;
            trendingScores.put(game.getId(), trendingScore);
        }

        return getTopScoredGames(highRatedGames, trendingScores, limit);
    }

}